package org.infodavid.common.impl.services.helpers;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.infodavid.common.annotations.AImplementation;
import org.infodavid.common.annotations.AImplementation.ERuntime;
import org.infodavid.common.dto.IUserGroupListItem.EUserRole;
import org.infodavid.common.impl.model.criteria.UserCriteriaImpl;
import org.infodavid.common.model.IUser;
import org.infodavid.common.model.IUserConnection;
import org.infodavid.common.model.criteria.IUserCriteria;
import org.infodavid.common.notifier.IMailCommand;
import org.infodavid.common.notifier.INotifierCommand;
import org.infodavid.common.notifier.exceptions.NotifierException;
import org.infodavid.common.notifier.impl.MailCommandImpl;
import org.infodavid.common.persistence.UserDataService;
import org.infodavid.common.services.IApplicationContext;
import org.infodavid.common.services.exception.IllegalOperationException;
import org.infodavid.common.services.exceptions.ServiceException;
import org.infodavid.common.services.helpers.NotificationHelper;
import org.infodavid.common.util.IVisitor;

/**
 * The Class NotificationHelperImpl.
 */
@AImplementation(value = NotificationHelper.class, runtime = ERuntime.DEFAULT)
public class NotificationHelperImpl extends NotificationHelper {

	/**
	 * The Constructor.
	 */
	protected NotificationHelperImpl() {
		super();
	}

	/**
	 * New command instance.
	 * @param <T> the generic type
	 * @param type the type of command
	 * @return the command
	 * @throws ServiceException the service exception
	 */
	@SuppressWarnings("unchecked")
	public <T extends INotifierCommand> T newCommandInstance(final Class<T> type)
	    throws ServiceException {
		T notification;

		if (type == null) {
			throw new IllegalOperationException("Type of the notification is not specified");
		}
		else if (IMailCommand.class.equals(type)) {
			notification = (T)new MailCommandImpl();
		}
		else {
			throw new IllegalOperationException("Type of the notification is not supported");
		}

		return notification;
	}

	/**
	 * Notify users.
	 * @param context the context
	 * @param role the role
	 * @param visitor the visitor
	 */
	public void notifyUsers(final IApplicationContext context, final EUserRole role,
	    final IVisitor<IUser,Object> visitor) {
		if (role == null) {
			throw new IllegalArgumentException("Cannot send notification, role is not valid");
		}

		if (visitor == null) {
			throw new IllegalArgumentException("Cannot send notification, visitor is not valid");
		}

		final Map<String,Object> inputs = new HashMap<String,Object>();

		inputs.put(CONTEXT_VAR, context);

		final int batchSize = 100;
		final UserDataService userService = UserDataService.getInstance();
		final List<IUser> results = new ArrayList<IUser>(batchSize);
		final IUserCriteria criteria = new UserCriteriaImpl();
		long retrieved = 0;
		long count;

		criteria.setPageStart(Long.valueOf(0));
		criteria.setPageSize(Integer.valueOf(batchSize));

		try {
			do {
				results.clear();

				count = userService.findByRole(context.getPersistenceSession(), role, results, criteria);

				retrieved += results.size();

				criteria.setPageStart(Long.valueOf(retrieved));

				if (!results.isEmpty()) {
					for (final IUser item : results) {
						visitor.visit(item);
					}
				}
			}
			while (!results.isEmpty() && retrieved < count);
		}
		catch (final Throwable e) {
			handle(e, e.getMessage(), this);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see
	 * org.infodavid.common.services.helpers.NotificationHelper#notifyUserPasswordChange(org.infodavid
	 * .common.services.IApplicationContext, org.infodavid.common.model.IUser)
	 */
	@Override
	public void notifyUserPasswordChange(final IApplicationContext context, final IUser user)
	    throws ServiceException, NotifierException {}

	/*
	 * (non-Javadoc)
	 * @see
	 * org.infodavid.common.services.helpers.NotificationHelper#notifyUserPasswordReset(org.infodavid.
	 * common.services.IApplicationContext, org.infodavid.common.model.IUser)
	 */
	@Override
	public void notifyUserPasswordReset(final IApplicationContext context, final IUser user)
	    throws ServiceException, NotifierException {}

	/*
	 * (non-Javadoc)
	 * @see
	 * org.infodavid.common.services.helpers.NotificationHelper#notifyUserRegistration(org.infodavid.common
	 * .services.IApplicationContext, org.infodavid.common.model.IUser)
	 */
	@Override
	public void notifyUserRegistration(final IApplicationContext context, final IUser user)
	    throws ServiceException, NotifierException {}

	/*
	 * (non-Javadoc)
	 * @see
	 * org.infodavid.common.services.helpers.NotificationHelper#notifyUserConnectionChanges(org.infodavid
	 * .common.services.IApplicationContext, org.infodavid.common.model.IUserConnection)
	 */
	@Override
	public void notifyUserConnectionChanges(final IApplicationContext context,
	    final IUserConnection item) throws ServiceException, NotifierException {}

	/*
	 * (non-Javadoc)
	 * @see
	 * org.infodavid.common.services.helpers.NotificationHelper#notifyUserConnectionSubmitted(org.infodavid
	 * .common.services.IApplicationContext, org.infodavid.common.model.IUserConnection)
	 */
	@Override
	public void notifyUserConnectionSubmitted(final IApplicationContext context,
	    final IUserConnection connection) throws ServiceException, NotifierException {}
}
